package com.winit.jumpServer.task;

import com.winit.common.base.beans.LoginUser;
import com.winit.common.util.*;
import com.winit.deploy.bean.DeployEnum;
import com.winit.deploy.manager.DeployManager;
import com.winit.deploy.util.DeployUtil;
import com.winit.jumpServer.bean.PushRecordInfo;
import com.winit.jumpServer.util.JumpServerListInfo;
import com.winit.project.core.branch.Project;
import com.winit.project.util.ProjectPushUtil;
import com.winit.project.util.ProjectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * Created by wangjian on 16/1/18.
 */
public class PushTask implements Runnable {


    private static final Logger logger = LoggerFactory.getLogger(PushTask.class);

    private PushRecordInfo pushRecordInfo;
    private DeployManager deployManager;
    private LoginUser userInfo;

    private boolean testPass;

    public PushTask(PushRecordInfo pushRecordInfo, boolean testPass) {
        this.pushRecordInfo = pushRecordInfo;
        this.testPass = testPass;
    }

    public PushTask(PushRecordInfo pushRecordInfo, boolean testPass, DeployManager deployManager, LoginUser userInfo) {
        this.pushRecordInfo = pushRecordInfo;
        this.testPass = testPass;
        this.deployManager = deployManager;
        this.userInfo = userInfo;
    }

    public void run() {
        logger.info("推送线程开启......");
        logger.info("参数：pushRecordInfo=" + ObjectToString.getString(pushRecordInfo));

        StringBuffer path = new StringBuffer();
        path.append(ConfigUtil.getValue("rootPath")).append("Beetle/pushRecord/").append(pushRecordInfo.getRecordName()).append("/record-info.json");
        pushRecordInfo.setStatus(Constants.JUMPSERVER_PUSH_STATUS_ON);
        pushRecordInfo.setStartTime(DateUtil.formatDate(new Date(), "yyyy-MM-dd HH:mm:ss"));
        boolean flag = JSONFileUtil.saveFileJson(path.toString(), pushRecordInfo);

        //校验推送锁文件是否存在
        StringBuffer lock = new StringBuffer();
        lock.append(ProjectUtil.getProjectFilePath(pushRecordInfo.getProjectName())).append("/push_").append(pushRecordInfo.getEditionNum()).append("_");

        if (Constants.JUMPSERVER_PUSH_FROM_DEFULT.equals(pushRecordInfo.getPushFrom())) {
            lock.append(pushRecordInfo.getJumpServerIp()).append(".lock");
        } else {
            lock.append(JumpServerListInfo.jumpServerInfo.get(pushRecordInfo.getPushFrom()).getIp()).append(".lock");
        }
        File lockFile = new File(lock.toString());
        if (lockFile.exists()) {
            logger.info("该工程版本正在推送中,不用重复推送.info=" + ObjectToString.getString(pushRecordInfo));
            pushRecordInfo.setStatus(Constants.JUMPSERVER_PUSH_STATUS_FAIL);
            pushRecordInfo.setDesc("该工程版本正在推送中,不用重复推送");
            JSONFileUtil.saveFileJson(path.toString(), pushRecordInfo);
            return;
        }

        try {
            lockFile.createNewFile();
        } catch (IOException e) {
            logger.warn("创建发布锁文件异常,path=" + lockFile.getAbsolutePath(), e);
        }

        String editionPath = ProjectUtil.getProjectFilePath(pushRecordInfo.getProjectName()) + pushRecordInfo.getEditionNum();
        try {
            this.updateProjectPushStatus(PushStatusEnum.IN_PUSH, "正在推送中");

            ProjectPushUtil.createPushPackage(pushRecordInfo.getProjectName(), editionPath);

            if (flag) {
                String str = "";
                //一级推送
                if (Constants.JUMPSERVER_PUSH_FROM_DEFULT.equals(pushRecordInfo.getPushFrom())) {
                    str = pushLevelOne("");
                } else {
                    //二级推送
                    //先推送一级跳板机,成功后再推送二级跳板机
                    str = pushLevelOne(pushRecordInfo.getPushFrom());
                    logger.info("执行一级跳板机推送,返回:" + str);
                    if (str.startsWith("success")) {
                        str = pushLevelTwo();
                        logger.info("执行二级跳板机推送,返回:" + str);
                    }
                }

                logger.info("执行跳板机推送,返回:" + str);
                if (str.startsWith("success")) {
                    logger.info("推送成功,info=" + ObjectToString.getString(pushRecordInfo));
                    pushRecordInfo.setStatus(Constants.JUMPSERVER_PUSH_STATUS_SUCCESS);
                    pushRecordInfo.setDesc("推送成功");
                    JSONFileUtil.saveFileJson(path.toString(), pushRecordInfo);
                    this.updateProjectPushStatus(PushStatusEnum.PUSH_SUCCESS, "推送成功");

                    //推送成功后,通过点击测试通过创建的推送,需要保存测试通过版本
                    if (testPass) {
                        DeployUtil.updateProjectVersion(pushRecordInfo.getProjectName(), pushRecordInfo.getEditionNum(), DeployEnum.TESTPASS);
                        //如果是who工程，则自动部署，加上个开关
                        String autoDeployWho = ConfigUtil.getValue("auto_deploy_who");
                        if (!StringUtils.isEmpty(autoDeployWho) && "true".equals(autoDeployWho) && "who".equals(ProjectUtil.getTrunkProjectName(pushRecordInfo.getProjectName()))) {
                            if (Constants.JUMPSERVER_PUSH_FROM_DEFULT.equals(pushRecordInfo.getPushFrom())) {
                                deployManager.autoDeployWho(userInfo, pushRecordInfo.getJumpServerIp(), pushRecordInfo.getProjectName(), pushRecordInfo.getEditionNum());
                            } else {
                                deployManager.autoDeployWho(userInfo, pushRecordInfo.getPushFrom(), pushRecordInfo.getProjectName(), pushRecordInfo.getEditionNum());
                                deployManager.autoDeployWho(userInfo, pushRecordInfo.getJumpServerIp(), pushRecordInfo.getProjectName(), pushRecordInfo.getEditionNum());
                            }
                        }
                    }
                } else {
                    logger.info("推送失败,info=" + ObjectToString.getString(pushRecordInfo) + ",return=" + str);
                    pushRecordInfo.setStatus(Constants.JUMPSERVER_PUSH_STATUS_FAIL);
                    pushRecordInfo.setDesc(str);
                    JSONFileUtil.saveFileJson(path.toString(), pushRecordInfo);
                    this.updateProjectPushStatus(PushStatusEnum.PUSH_ERROR, "推送失败," + str);
                }
            }
        } catch (Exception e) {
            logger.error("执行推送异常," + ObjectToString.getString(pushRecordInfo), e);
            this.updateProjectPushStatus(PushStatusEnum.PUSH_EXCEPTION, "推送异常," + e.getMessage());
        } finally {
            if (lockFile.exists()) {
                lockFile.delete();
            }
            ProjectPushUtil.delPushPackage(pushRecordInfo.getProjectName(), editionPath);

            List<String> list = JumpServerListInfo.pushTaskList.get(pushRecordInfo.getProjectName());
            if (list != null) {
                list.remove(pushRecordInfo.getJumpServerIp());
                JumpServerListInfo.pushTaskList.put(pushRecordInfo.getProjectName(), list);
            }

        }
        logger.info("推送线程结束......");
    }

    /**
     * 一级跳板机推送
     *
     * @return
     */
    private String pushLevelOne(String ip) {
        String jumpServerIp = StringUtils.isEmpty(ip) ? pushRecordInfo.getJumpServerIp() : ip;
        String[] param = new String[12];
        param[0] = "bash";
        param[1] = Constants.SHELL_PATH + "shell/jumpServer/beetle_jumpserver_push.sh";
        param[2] = ConfigUtil.getValue("rootPath");
        param[3] = pushRecordInfo.getProjectName();
        param[4] = jumpServerIp;
        param[5] = pushRecordInfo.getRecordName();
        param[6] = pushRecordInfo.getEditionNum();
        param[7] = Constants.SSH_LOGIN_USER;
        param[8] = Constants.SSH_KEY_FILE;
        param[9] = JumpServerListInfo.jumpServerInfo.get(jumpServerIp).getSshPort();
        param[10] = Constants.SHELL_PATH;
        param[11] = ProjectUtil.getProjectFilePath(pushRecordInfo.getProjectName());

        return ShellRunUtil.runShell(param);
    }

    /**
     * 二级跳板机推送
     *
     * @return
     */
    private String pushLevelTwo() {
        String[] param = new String[14];
        param[0] = "bash";
        param[1] = Constants.SHELL_PATH + "shell/jumpServer/beetle_jumpserver_push_two.sh";
        param[2] = ConfigUtil.getValue("rootPath");
        param[3] = pushRecordInfo.getProjectName();
        param[4] = pushRecordInfo.getJumpServerIp();
        param[5] = pushRecordInfo.getRecordName();
        param[6] = pushRecordInfo.getEditionNum();
        param[7] = Constants.SSH_LOGIN_USER;
        param[8] = Constants.SSH_KEY_FILE;
        param[9] = JumpServerListInfo.jumpServerInfo.get(pushRecordInfo.getJumpServerIp()).getSshPort();
        param[10] = Constants.SHELL_PATH;
        param[11] = JumpServerListInfo.jumpServerInfo.get(pushRecordInfo.getPushFrom()).getIp();
        param[12] = JumpServerListInfo.jumpServerInfo.get(pushRecordInfo.getPushFrom()).getSshPort();
        param[13] = ProjectUtil.getProjectFilePath(pushRecordInfo.getProjectName());

        return ShellRunUtil.runShell(param);
    }

    private void updateProjectPushStatus(PushStatusEnum statusEnum, String desc) {
        try {
            Project project = new Project(pushRecordInfo.getProjectName(), true);
            if (testPass || project.getProjectStatus().getPushEdition().equals(pushRecordInfo.getEditionNum())) {
                project.updatePushStatus(statusEnum, desc, pushRecordInfo.getEditionNum());
            }
        } catch (Exception e) {
            logger.error("com.winit.jumpServer.task.PushTask.updateProjectPushStatus 异常.projectName="
                    + pushRecordInfo.getProjectName() + ",editionNum=" + pushRecordInfo.getEditionNum(), e);
        }
    }
}
